Shipping Go by Joel Holmes

Shipping Go by Joel Holmes

Author:Joel Holmes [Joel Holmes]
Language: eng
Format: epub
Publisher: Manning Publications
Published: 2023-07-10T00:00:00+00:00


6.6 Fake

Finally, we will add one more set of unit tests for a client that calls an external API. Here, we come up against a different type of interface testing, this time with an API that we don’t control. Like our other interfaces tests, we can establish a contract or definition of what this API should look like and use a fake to simulate it.

WARNING We don’t have control over the other API, just our own, and if something were to change on the other API, we could end up with failures. This fake is simulating an external dependency, or a system outside our control, and therefore should be monitored and heavily logged in case failures such as outages occur. Advanced system patterns such as Circuit Breakers should be used, but they are outside the context of this book. I suggest Cloud Native Patterns (Manning, 2019) by Cornelia Davis.

A fake is an object, struct, or service with limited capabilities. So far, we have described stubs and mocks in the context of testing. We will use the term fake as a definition of an object that stands in for an external service. Fakes provide this last category of tools to help us verify the base units of our code before we start moving toward integrating with external integration.

Go provides the ability to create a test server to call against, which makes our testing easier. We will use a fake HTTP server to build our fake to test a client we create. Let’s set up our suite before we get into the details of the implementation. First, create the files using

touch translation/client.go touch translation/client_test.go

and then add the code in the following listing.

Listing 6.21 client_test.go

package translation_test import ( "encoding/json" "io" "io/ioutil" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" ) func TestHelloClientSuite(t *testing.T) { suite.Run(t, new(HelloClientSuite)) } type HelloClientSuite struct { suite.Suite mockServerService *MockService server *httptest.Server ❶ underTest translation.HelloClient ❷ } type MockService struct { mock.Mock } func (m *MockService) Translate(word, language string) (string, error) { ❸ args := m.Called(word, language) return args.String(0), args.Error(1) }

❶ Use a test server to run against

❷ We are going to be testing the interface defined here.

❸ Similar mock to the ones we’ve seen before to help us inject values into the handler

To set up our client test, we will need to create a handler that captures the message to test what the client passes (see the following listing).

Listing 6.22 client_test.go

func (suite *HelloClientSuite) SetupSuite() { ❶ suite.mockServerService = new(MockService) handler := func(w http.ResponseWriter, r *http.Request) { b, _ := ioutil.ReadAll(r.Body) defer r.Body.Close() var m map[string]interface{} _ = json.Unmarshal(b, &m) word := m["word"].(string) language := m["language"].(string) resp, err := suite.mockServerService.Translate(word, language) ❷ if err != nil { http.Error(w, "error", 500) } if resp == "" { http.Error(w, "missing", 404) } w.Header().Set("Content-Type", "application/json") _, _ = io.WriteString(w, resp) } mux := http.NewServeMux() mux.HandleFunc("/", handler) suite.server = httptest.NewServer(mux) ❸ } func (suite *HelloClientSuite) TearDownSuite() { suite.server.Close() ❹ }

❶ SetupSuite is used because we don’t want to create a new server for each test, just this group of tests.



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.